海鸥优化算法 (Seagull Optimization Algorithm,SOA) 是由 Gaurav Dhiman 等人于 2019 年提出的一种全新的元启发式智能优化算法,它是一种通过模拟海鸥迁徙和肷击行为来求解优化问题的算法。
海鸥是遍布全球的海鸟, 种类繁多且大小和身长各不相同。海鸦是杂食动物, 吃昆虫、 鱼、爬行动物、两栖动物和蚯蚓等。大多数海鸥的身体覆盖着白色的羽毛, 经常用面包屑来吸引鱼群, 用脚发出雨水落下的声音来吸引藏在地下的蚯蚓。海袓可以喝淡水和盐水, 通过眼睛上方的一对特殊腺体, 将盐从它们的体内排出。海鸥以群居方式生活, 利用群体智彗来寻找和攻击猎物。海鸥最重要的特征是迁徙和攻击行为, 迁徙是指动物根据季节更替从一个地方移动到另一个地方, 寻找丰富的食物来源以便获取足够能量。迁徙时每只海鴎的所在位置不同, 以避免相互碰撞。在一个群体中, 海鸥可以朝着最佳位置的方向前进并改变自身所在的位置。海鸥经常会攻击候鸟并在进攻时呈现螺旋形的运动形态。
在海鸥迁徙过程中, 海鸥优化算法模拟海鸥群体如何从一个位置移动到另一个位置。在这个阶段, 海鸥应该满足避免碰撞这一条件。为了避免与相邻的其他海鸥碰撞, 该算法采用附加变量 $A$ 计算海鸥的新位置, 即 $$ C_{\mathrm{s}}(t)=A \times P_{\mathrm{s}}(t) $$ 其中, $C_{\mathrm{s}}(t)$ 表示不与其他海鸥存在位置冲突的新位置; $P_{\mathrm{s}}(t)$ 为海鸥当前位置; $t$ 表示当前迭 代次数; $A$ 表示海鸥在给定搜索空间中的运动行为, 可表示为 $$ A=f_{\mathrm{c}}-\left(t \times\left(f_{\mathrm{c}} / \mathrm{Max}_{\text {iteration }}\right)\right) $$ 其中, $f_{\mathrm{c}}$ 表示可以控制变量 $A$ 的变化频率, 其值从 2 线性减小到 $0 ; \mathrm{Max}_{\text {iteration }}$ 表示最大迭代 次数; $t$ 表示当前迭代次数。 海鸥在迁徙过程中, 在避免了与其他海鸥的位置重合后, 首先会计算最佳位置的方向, 并向最佳位置移动。 $$ M_{\mathrm{s}}(t)=B \times\left(P_{\mathrm{bs}}(t)-P_{\mathrm{s}}(t)\right) $$ 其中, $M_{\mathrm{s}}(t)$ 表示最佳位置的方向; $P_{\mathrm{bs}}(t)$ 表示当前海鸥最佳位置; $P_{\mathrm{s}}(t)$ 表示海鸥当前位置; $B$ 是平衡全局搜索和局部搜索的随机数, 即 $$ B=2 \times A^2 \times r_{\mathrm{d}} $$
其中, $r_{\mathrm{d}}$ 为区间 $[0,1]$ 内的随机数。 海鸥在获取最佳位置的方向后, 会向最佳位置移动, 到达新的位置。 $$ D_{\mathrm{s}}(t)=\left|C_{\mathrm{s}}(t)+M_{\mathrm{s}}(t)\right| $$ 其中, $D_{\mathrm{s}}(t)$ 表示海鸧的新位置; $C_{\mathrm{s}}(t)$ 表示不与其他海鸥存在位置冲突的位置; $M_{\mathrm{s}}(t)$ 表示取 佳位置的方向。
海鸥在迁徙过程中可以不断改变攻击角度和速度, 同时用翅膀和重量保持高度。当海鸥攻击猎物时, 它们就在空中进行螺旋运动。将海鸥在 $x, y, z$ 平面中的运动行为描述为 $$ \left\{\begin{array}{l} x=r \times \cos (\theta) \\ y=r \times \sin (\theta) \\ z=r \times \theta \\ r=u \times \mathrm{e}^{\theta v} \end{array}\right. $$ 其中, $r$ 是每个螺旋的半径; $\theta$ 为区间 $[0,2 \pi]$ 内的随机角度值; $u$ 和 $v$ 是螺旋形状的相关常数; $\mathrm{e}$ 是自然对数的底数。 当 $u=1, v=0.1, \theta$ 从 0 递增到 $2 \pi$ 时, 以 $x, y, z$ 建立坐标系, 海鸥的运动轨迹如下图所示。
海鸥攻击猎物后的位置用下式表示。 $$ P_{\mathrm{s}}(t)=D_{\mathrm{s}}(t) \times x \times y \times z+P_{\text {bs }}(t) $$ 其中, $P_{\mathrm{s}}(t)$ 表示海鸥攻击猎物后的位置; $P_{\mathrm{bs}}(t)$ 表示当前海鸥的最佳位置。 $6.1 .3$ 海鸥优化算法流程 海鸥优化算法的流程图如下图所示。
海鸥优化算法步骤如下:
步骤 1:初始化海鸥优化算法的相关参数。
步骤 2: 根据种群数量与边界来初始化种群位置。
步骤 3: 计算适应度值并保留全局最优位置。
步骤 4: 海鸥迁徙。
步骤 5:海鸥攻击猎物。
步骤 6: 判断是否满足算法停止条件, 若满足, 则输出最优位置; 否则重复步骤 3-6。
import numpy as np
import copy
import numpy as np
from matplotlib import pyplot as plt
def initialization(pop,ub,lb,dim):
''' 种群初始化函数'''
'''
pop:为种群数量
dim:每个个体的维度
ub:每个维度的变量上边界,维度为[dim,1]
lb:为每个维度的变量下边界,维度为[dim,1]
X:为输出的种群,维度[pop,dim]
'''
X = np.zeros([pop,dim]) #声明空间
for i in range(pop):
for j in range(dim):
X[i,j]=(ub[j]-lb[j])*np.random.random()+lb[j] #生成[lb,ub]之间的随机数
return X
def BorderCheck(X,ub,lb,pop,dim):
'''边界检查函数'''
'''
dim:为每个个体数据的维度大小
X:为输入数据,维度为[pop,dim]
ub:为个体数据上边界,维度为[dim,1]
lb:为个体数据下边界,维度为[dim,1]
pop:为种群数量
'''
for i in range(pop):
for j in range(dim):
if X[i,j]>ub[j]:
X[i,j] = ub[j]
elif X[i,j]<lb[j]:
X[i,j] = lb[j]
return X
def CaculateFitness(X,fun):
'''计算种群的所有个体的适应度值'''
pop = X.shape[0]
fitness = np.zeros([pop, 1])
for i in range(pop):
fitness[i] = fun(X[i, :])
return fitness
def SortFitness(Fit):
'''适应度值排序'''
'''
输入为适应度值
输出为排序后的适应度值,和索引
'''
fitness = np.sort(Fit, axis=0)
index = np.argsort(Fit, axis=0)
return fitness,index
def SortPosition(X,index):
'''根据适应度值对位置进行排序'''
Xnew = np.zeros(X.shape)
for i in range(X.shape[0]):
Xnew[i,:] = X[index[i],:]
return Xnew
def SOA(pop, dim, lb, ub, MaxIter, fun):
'''海鸥优化算法'''
'''
输入:
pop:为种群数量
dim:每个个体的维度
ub:为个体上边界信息,维度为[1,dim]
lb:为个体下边界信息,维度为[1,dim]
fun:为适应度函数接口
MaxIter:为最大迭代次数
输出:
GbestScore:最优解对应的适应度值
GbestPositon:最优解
Curve:迭代曲线
'''
fc = 2 #可调
X = initialization(pop,ub,lb,dim) #初始化种群
fitness = CaculateFitness(X,fun) #计算适应度值
fitness,sortIndex = SortFitness(fitness) #对适应度值排序
X = SortPosition(X,sortIndex) #种群排序
GbestScore = copy.copy(fitness[0])
GbestPositon = np.zeros([1,dim])
GbestPositon[0,:] = copy.copy(X[0,:])
Curve = np.zeros([MaxIter,1])
MS = np.zeros([pop,dim])
CS = np.zeros([pop,dim])
DS = np.zeros([pop,dim])
X_new = copy.copy(X)
for i in range(MaxIter):
print("第"+str(i)+"次迭代")
Pbest = X[0,:]
for j in range(pop):
#计算Cs
A = fc - (i*(fc/MaxIter))
CS[j,:]=X[j,:]*A
#计算Ms
rd=np.random.random()
B = 2*(A**2)*rd
MS[j,:] = B*(Pbest - X[j,:])
#计算Ds
DS[j,:] = np.abs(CS[j,:] + MS[j,:])
#局部搜索
u = 1
v = 1
theta = np.random.random()
r = u*np.exp(theta*v)
x = r*np.cos(theta*2*np.pi)
y = r*np.sin(theta*2*np.pi)
z = r*theta
#攻击
X_new[j,:] = x*y*z*DS[j,:] + Pbest
X = BorderCheck(X_new,ub,lb,pop,dim) #边界检测
fitness = CaculateFitness(X,fun) #计算适应度值
fitness,sortIndex = SortFitness(fitness) #对适应度值排序
X = SortPosition(X,sortIndex) #种群排序
if(fitness[0]<=GbestScore): #更新全局最优
GbestScore = copy.copy(fitness[0])
GbestPositon[0,:] = copy.copy(X[0,:])
Curve[i] = GbestScore
return GbestScore, GbestPositon, Curve
'''适应度函数'''
def fun(X):
O=X[0]**2 + X[1]**2
return O
'''海鸥优化算法求解x1^2 + x2^2的最小值'''
'''主函数 '''
#设置参数
pop = 50 #种群数量
MaxIter = 100 #最大迭代次数
dim = 2 #维度
lb = -10*np.ones(dim) #下边界
ub = 10*np.ones(dim)#上边界
#适应度函数选择
fobj = fun
GbestScore,GbestPositon,Curve = SOA(pop,dim,lb,ub,MaxIter,fobj)
print('最优适应度值:',GbestScore)
print('最优解[x1,x2]:',GbestPositon)
#绘制适应度曲线
plt.figure(1)
plt.plot(Curve,'r-',linewidth=2)
plt.xlabel('Iteration',fontsize='medium')
plt.ylabel("Fitness",fontsize='medium')
plt.grid()
plt.title('SOA',fontsize='large')
plt.show()
参考资料:
import numpy as np
import copy
import numpy as np
from matplotlib import pyplot as plt
def initialization(pop,ub,lb,dim):
''' 种群初始化函数'''
'''
pop:为种群数量
dim:每个个体的维度
ub:每个维度的变量上边界,维度为[dim,1]
lb:为每个维度的变量下边界,维度为[dim,1]
X:为输出的种群,维度[pop,dim]
'''
X = np.zeros([pop,dim]) #声明空间
for i in range(pop):
for j in range(dim):
X[i,j]=(ub[j]-lb[j])*np.random.random()+lb[j] #生成[lb,ub]之间的随机数
return X
def BorderCheck(X,ub,lb,pop,dim):
'''边界检查函数'''
'''
dim:为每个个体数据的维度大小
X:为输入数据,维度为[pop,dim]
ub:为个体数据上边界,维度为[dim,1]
lb:为个体数据下边界,维度为[dim,1]
pop:为种群数量
'''
for i in range(pop):
for j in range(dim):
if X[i,j]>ub[j]:
X[i,j] = ub[j]
elif X[i,j]<lb[j]:
X[i,j] = lb[j]
return X
def CaculateFitness(X,fun):
'''计算种群的所有个体的适应度值'''
pop = X.shape[0]
fitness = np.zeros([pop, 1])
for i in range(pop):
fitness[i] = fun(X[i, :])
return fitness
def SortFitness(Fit):
'''适应度值排序'''
'''
输入为适应度值
输出为排序后的适应度值,和索引
'''
fitness = np.sort(Fit, axis=0)
index = np.argsort(Fit, axis=0)
return fitness,index
def SortPosition(X,index):
'''根据适应度值对位置进行排序'''
Xnew = np.zeros(X.shape)
for i in range(X.shape[0]):
Xnew[i,:] = X[index[i],:]
return Xnew
def SOA(pop, dim, lb, ub, MaxIter, fun):
'''海鸥优化算法'''
'''
输入:
pop:为种群数量
dim:每个个体的维度
ub:为个体上边界信息,维度为[1,dim]
lb:为个体下边界信息,维度为[1,dim]
fun:为适应度函数接口
MaxIter:为最大迭代次数
输出:
GbestScore:最优解对应的适应度值
GbestPositon:最优解
Curve:迭代曲线
'''
fc = 2 #可调
X = initialization(pop,ub,lb,dim) #初始化种群
fitness = CaculateFitness(X,fun) #计算适应度值
fitness,sortIndex = SortFitness(fitness) #对适应度值排序
X = SortPosition(X,sortIndex) #种群排序
GbestScore = copy.copy(fitness[0])
GbestPositon = np.zeros([1,dim])
GbestPositon[0,:] = copy.copy(X[0,:])
Curve = np.zeros([MaxIter,1])
MS = np.zeros([pop,dim])
CS = np.zeros([pop,dim])
DS = np.zeros([pop,dim])
X_new = copy.copy(X)
for i in range(MaxIter):
print("第"+str(i)+"次迭代")
Pbest = X[0,:]
for j in range(pop):
#计算Cs
A = fc - (i*(fc/MaxIter))
CS[j,:]=X[j,:]*A
#计算Ms
rd=np.random.random()
B = 2*(A**2)*rd
MS[j,:] = B*(Pbest - X[j,:])
#计算Ds
DS[j,:] = np.abs(CS[j,:] + MS[j,:])
#局部搜索
u = 1
v = 1
theta = np.random.random()
r = u*np.exp(theta*v)
x = r*np.cos(theta*2*np.pi)
y = r*np.sin(theta*2*np.pi)
z = r*theta
#攻击
X_new[j,:] = x*y*z*DS[j,:] + Pbest
X = BorderCheck(X_new,ub,lb,pop,dim) #边界检测
fitness = CaculateFitness(X,fun) #计算适应度值
fitness,sortIndex = SortFitness(fitness) #对适应度值排序
X = SortPosition(X,sortIndex) #种群排序
if(fitness[0]<=GbestScore): #更新全局最优
GbestScore = copy.copy(fitness[0])
GbestPositon[0,:] = copy.copy(X[0,:])
Curve[i] = GbestScore
return GbestScore, GbestPositon, Curve
'''适应度函数'''
def fun(X):
O=X[0]**2 + X[1]**2
return O
'''海鸥优化算法求解x1^2 + x2^2的最小值'''
'''主函数 '''
#设置参数
pop = 50 #种群数量
MaxIter = 100 #最大迭代次数
dim = 2 #维度
lb = -10*np.ones(dim) #下边界
ub = 10*np.ones(dim)#上边界
#适应度函数选择
fobj = fun
GbestScore,GbestPositon,Curve = SOA(pop,dim,lb,ub,MaxIter,fobj)
print('最优适应度值:',GbestScore)
print('最优解[x1,x2]:',GbestPositon)
#绘制适应度曲线
plt.figure(1)
plt.plot(Curve,'r-',linewidth=2)
plt.xlabel('Iteration',fontsize='medium')
plt.ylabel("Fitness",fontsize='medium')
plt.grid()
plt.title('SOA',fontsize='large')
plt.show()
第0次迭代 第1次迭代 第2次迭代 第3次迭代 第4次迭代 第5次迭代 第6次迭代 第7次迭代 第8次迭代 第9次迭代 第10次迭代 第11次迭代 第12次迭代 第13次迭代 第14次迭代 第15次迭代 第16次迭代 第17次迭代 第18次迭代 第19次迭代 第20次迭代 第21次迭代 第22次迭代 第23次迭代 第24次迭代 第25次迭代 第26次迭代 第27次迭代 第28次迭代 第29次迭代 第30次迭代 第31次迭代 第32次迭代 第33次迭代 第34次迭代 第35次迭代 第36次迭代 第37次迭代 第38次迭代 第39次迭代 第40次迭代 第41次迭代 第42次迭代 第43次迭代 第44次迭代 第45次迭代 第46次迭代 第47次迭代 第48次迭代 第49次迭代 第50次迭代 第51次迭代 第52次迭代 第53次迭代 第54次迭代 第55次迭代 第56次迭代 第57次迭代 第58次迭代 第59次迭代 第60次迭代 第61次迭代 第62次迭代 第63次迭代 第64次迭代 第65次迭代 第66次迭代 第67次迭代 第68次迭代 第69次迭代 第70次迭代 第71次迭代 第72次迭代 第73次迭代 第74次迭代 第75次迭代 第76次迭代 第77次迭代 第78次迭代 第79次迭代 第80次迭代 第81次迭代 第82次迭代 第83次迭代 第84次迭代 第85次迭代 第86次迭代 第87次迭代 第88次迭代 第89次迭代 第90次迭代 第91次迭代 第92次迭代 第93次迭代 第94次迭代 第95次迭代 第96次迭代 第97次迭代 第98次迭代 第99次迭代 最优适应度值: [2.44363384e-60] 最优解[x1,x2]: [[-1.43334450e-30 6.23824808e-31]]